package cn.itsource.ymcc.web.controller;

import cn.itsource.ymcc.common.result.JsonResult;
import cn.itsource.ymcc.config.HighlightResultMapper;
import cn.itsource.ymcc.domain.CourseDoc;
import cn.itsource.ymcc.mapper.CourseElasticsearchRepository;
import cn.itsource.ymcc.query.AggrPageList;
import cn.itsource.ymcc.query.AggrTermsBucket;
import cn.itsource.ymcc.query.CourseDocQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.BucketOrder;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/es")
public class EsCourseController {
    @Autowired
    private CourseElasticsearchRepository elasticsearchRepository;
    @Autowired
    private ElasticsearchRestTemplate restTemplate;
    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @PostMapping("/batchSaveCourseToEs")
    public JsonResult saveCourseToEs(@RequestBody List<CourseDoc> courseDoc){
        elasticsearchRepository.saveAll(courseDoc);
        return JsonResult.success();
    }

    @DeleteMapping("/delCourseById/{courseId}")
    public JsonResult delCourseById(@PathVariable("courseId")Long id){
        elasticsearchRepository.deleteById(id);
        return JsonResult.success();
    }

    @PostMapping("/getCourseDocByCourseIds")
    public JsonResult getCourseDocByCourseIds(@RequestBody List<Long> ids){
        Iterable<CourseDoc> allById = elasticsearchRepository.findAllById(ids);
        return JsonResult.success().setData(allById);
    }

    @PostMapping("/search")
    public JsonResult search(@RequestBody CourseDocQuery courseDocQuery){
        //第一次query
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //bool
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //没有任何一个条件
        if(StringUtils.hasText(courseDocQuery.getKeyword())){
            boolQueryBuilder.filter(QueryBuilders.matchQuery("name",courseDocQuery.getKeyword()));
        }
        if(courseDocQuery.getPriceMin() != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(courseDocQuery.getPriceMin()));
        }
        if(courseDocQuery.getPriceMax() != null){
            boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(courseDocQuery.getPriceMax()));
        }
        queryBuilder.withQuery(boolQueryBuilder);

        //分页  注意：SpringDataElasticsearch的当前页码是从0开始的
        Pageable pageable = PageRequest.of(courseDocQuery.getPageNo()-1, courseDocQuery.getPageSize());
        queryBuilder.withPageable(pageable);
        //排序
        if(StringUtils.hasText(courseDocQuery.getOrderField())){
            SortOrder sortOrder = SortOrder.ASC;
            if("desc".equalsIgnoreCase(courseDocQuery.getOrderType())){
                sortOrder = SortOrder.DESC;
            }
            SortBuilder sortBuilder = SortBuilders.fieldSort(courseDocQuery.getOrderField()).order(sortOrder);
            queryBuilder.withSort(sortBuilder);
        }
        //高亮的配置
        HighlightBuilder.Field  highlightField = new HighlightBuilder.Field("name")
                .preTags("<span style='color:red'>")
                .postTags("</span>");

        queryBuilder.withHighlightFields(highlightField);


        //聚合查询,按照机构名字聚合，安装数量倒排
        queryBuilder.addAggregation(AggregationBuilders
                .terms("gradeNameAgg") //聚合名字
                .field("gradeName")	//聚合的字段
                .order(BucketOrder.count(false)).size(20));//排序后取前20条


//        Page<CourseDoc> page = elasticsearchRepository.search(queryBuilder.build());
        AggregatedPage<CourseDoc> page = restTemplate.queryForPage(queryBuilder.build(), CourseDoc.class, highlightResultMapper);

        System.out.println("当前页码："+page.getNumber());
        System.out.println("每页条数："+page.getSize());
        System.out.println("总条数："+page.getTotalElements());
        System.out.println("总页数："+page.getTotalPages());
        System.out.println("当前页条数："+page.getNumberOfElements());
        //查询出来的数据
//        Map<String,Object> result = new HashMap<>();
//        result.put("total",page.getTotalElements());
//        result.put("rows",page.getContent());
        AggrPageList aggrPageList = new AggrPageList(page.getTotalElements(), page.getContent(),getAggrResult(page));
        return JsonResult.success().setData(aggrPageList);
    }

    private Map<String, List<AggrTermsBucket>> getAggrResult(AggregatedPage<CourseDoc> page) {
        //用来封装聚合结果
        Map<String,List<AggrTermsBucket>> aggrMap = new HashMap<>();

        //遍历聚合结果
        Aggregations aggregations = page.getAggregations();

        Map<String, Aggregation> stringAggregationMap = aggregations.asMap();

        Set<Map.Entry<String, Aggregation>> entries = stringAggregationMap.entrySet();

        entries.forEach(e->{
            //集合的名字
            String key = e.getKey();
            //集合的值的处理
            ParsedStringTerms value = (ParsedStringTerms)e.getValue();
            List<? extends Terms.Bucket> buckets = value.getBuckets();

            //使用lomda 把  List<StringTerms.Bucket>  转成  List<AggrTermsVo>
            List<AggrTermsBucket> aggrTermsVos = buckets.stream().map(bucket -> {
                return new AggrTermsBucket(bucket.getKeyAsString(), bucket.getDocCount());
            }).collect(Collectors.toList());

            aggrMap.put(key, aggrTermsVos);
        });
        return aggrMap;
    }
}
